package com.opdar.athena.client.agent.base;

import com.opdar.athena.client.agent.annotations.Commond;
import com.opdar.athena.client.agent.annotations.MessageType;
import com.opdar.athena.client.agent.server.IoSession;
import com.opdar.athena.base.Message;
import com.opdar.athena.utils.MessageUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

/**
 * 全局配置
 * Created by shiju on 2017/6/27.
 */
public class Configuration {
    /**
     * 单机承载量，超过限制则不接待客户端，-1为不限制
     */
    private Integer maxClient = -1;
    private String project = "ATHENA";
    private Integer version = 1;
    private long checkTime = 60000;
    private int checkFrequency = 2;
    private long heartbeatTime = 45000;
    private int heartbeatFrequency = 2;
    private static Configuration configuration;
    private ClassPathXmlApplicationContext context;
    private Map<Class<?>, InvokeHandler> messageTypeAction = new HashMap<Class<?>, InvokeHandler>();
    private AttributeKey<IoSession> sessions = AttributeKey.valueOf("session");
    private int port = 18181;
    private InetSocketAddress localAddress;

    public static Configuration getConfiguration() {
        if (configuration == null) configuration = new Configuration();
        return configuration;
    }

    public IoSession getSession(ChannelHandlerContext channelHandlerContext) {
        return channelHandlerContext.attr(sessions).get();
    }

    public long getCheckTime() {
        return checkTime;
    }

    public void setCheckTime(long checkTime) {
        this.checkTime = checkTime;
    }

    public int getCheckFrequency() {
        return checkFrequency;
    }

    public void setCheckFrequency(int checkFrequency) {
        this.checkFrequency = checkFrequency;
    }

    public Integer getMaxClient() {
        return maxClient;
    }

    public void setMaxClient(Integer maxClient) {
        this.maxClient = maxClient;
    }

    public String getProject() {
        return project;
    }

    public void setProject(String project) {
        this.project = project;
    }

    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    public ClassPathXmlApplicationContext getContext() {
        return context;
    }

    public void setContext(ClassPathXmlApplicationContext context) {
        this.context = context;
        scanMessageTypeAction(context);
    }

    private void scanMessageTypeAction(ApplicationContext context) {
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanName : beanDefinitionNames) {
            MessageType messageType = context.findAnnotationOnBean(beanName, MessageType.class);
            if (messageType != null) {
                //获取controller类
                Class clz = context.getType(beanName);
                MessageUtil.addMessageType(messageType.type(), messageType.value());
                Method[] methods = ReflectionUtils.getAllDeclaredMethods(clz);
                for (Method method : methods) {
                    method.setAccessible(true);
                    Commond commond = AnnotationUtils.findAnnotation(method, Commond.class);
                    if (commond != null) {
                        InvokeHandler handler = null;
                        if (messageTypeAction.containsKey(messageType.value())) {
                            handler = messageTypeAction.get(messageType.value());
                        } else {
                            messageTypeAction.put(messageType.value(), handler = new InvokeHandler());
                        }
                        handler.putCommand(commond.value(), method);
                        handler.setBeanName(beanName);
                    }
                }
            }
        }
    }

    public <T extends Message> Object invokeMessageTypeAction(T message, IoSession session) throws Throwable {
        Class<?> clz = message.getClass();
        if (messageTypeAction.containsKey(clz)) {
            InvokeHandler handler = messageTypeAction.get(clz);
            Object o = context.getBean(handler.getBeanName());
            String command = message.command();
            return handler.invoke(command, o, message, session);
        } else {
            throw new Throwable("消息类型不存在可执行方法");
        }
    }

    public void setSession(ChannelHandlerContext ctx, IoSession ioSession) {
        ctx.attr(sessions).set(ioSession);
    }

    public void removeSession(ChannelHandlerContext ctx) {
        ctx.attr(sessions).remove();
    }

    public long getHeartbeatTime() {
        return heartbeatTime;
    }

    public int getHeartbeatFrequency() {
        return heartbeatFrequency;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setLocalAddress(InetSocketAddress localAddress) {
        this.localAddress = localAddress;
    }

    public InetSocketAddress getLocalAddress() {
        return localAddress;
    }
}
